using System;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Terra.Data.Context;
using Terra.Data.Entities.Identity;

namespace Terra.Data.Repository.Identity;

/// <summary>
/// 刷新令牌仓储实现
/// </summary>
/// <remarks>
/// 该仓储提供以下功能：
/// <list type="bullet">
/// <item><description>刷新令牌的查询</description></item>
/// <item><description>刷新令牌的撤销</description></item>
/// <item><description>用户所有刷新令牌的批量撤销</description></item>
/// </list>
/// </remarks>
public class RefreshTokenRepository : RepositoryBase<RefreshToken, Guid>, IRefreshTokenRepository
{
    private readonly TerraDbContext _terraDbContext;

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="context">数据库上下文</param>
    /// <remarks>
    /// 通过构造函数注入的方式获取数据库上下文实例，用于数据库操作
    /// </remarks>
    public RefreshTokenRepository(TerraDbContext context) : base(context)
    {
        _terraDbContext = context;
    }

    /// <summary>
    /// 根据令牌值查找刷新令牌
    /// </summary>
    /// <param name="token">刷新令牌值</param>
    /// <returns>刷新令牌实体，如果未找到则返回 null</returns>
    /// <remarks>
    /// 该方法用于：
    /// <list type="bullet">
    /// <item><description>验证刷新令牌的有效性</description></item>
    /// <item><description>检查刷新令牌是否存在</description></item>
    /// <item><description>获取刷新令牌的详细信息</description></item>
    /// </list>
    /// </remarks>
    public async Task<RefreshToken> FindByTokenAsync(string token)
    {
        return await _terraDbContext.Set<RefreshToken>()
            .FirstOrDefaultAsync(r => r.Token == token);
    }

    /// <summary>
    /// 撤销指定用户的所有刷新令牌
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <remarks>
    /// 该方法用于：
    /// <list type="bullet">
    /// <item><description>用户注销时撤销所有活跃的刷新令牌</description></item>
    /// <item><description>安全威胁时强制用户在所有设备上登出</description></item>
    /// <item><description>管理员手动撤销用户的所有会话</description></item>
    /// </list>
    /// 
    /// 撤销流程：
    /// <list type="number">
    /// <item><description>查找用户所有未撤销的刷新令牌</description></item>
    /// <item><description>将所有令牌标记为已撤销</description></item>
    /// <item><description>更新令牌的最后修改时间</description></item>
    /// <item><description>保存更改到数据库</description></item>
    /// </list>
    /// </remarks>
    public async Task RevokeAllAsync(Guid userId)
    {
        var tokens = await _terraDbContext.Set<RefreshToken>()
            .Where(r => r.UserId == userId && !r.IsRevoked)
            .ToListAsync();

        foreach (var token in tokens)
        {
            token.IsRevoked = true;
            token.LastModifiedTime = DateTime.UtcNow;
        }

        await _terraDbContext.SaveChangesAsync();
    }

    /// <summary>
    /// 撤销单个刷新令牌
    /// </summary>
    /// <param name="token">要撤销的刷新令牌值</param>
    /// <remarks>
    /// 该方法用于：
    /// <list type="bullet">
    /// <item><description>用户在单个设备上登出</description></item>
    /// <item><description>检测到可疑活动时撤销特定会话</description></item>
    /// <item><description>令牌轮换时废弃旧令牌</description></item>
    /// </list>
    /// 
    /// 撤销流程：
    /// <list type="number">
    /// <item><description>查找指定的刷新令牌</description></item>
    /// <item><description>如果令牌存在且未被撤销：</description></item>
    /// <item><description>- 将令牌标记为已撤销</description></item>
    /// <item><description>- 更新最后修改时间</description></item>
    /// <item><description>- 保存更改到数据库</description></item>
    /// </list>
    /// </remarks>
    public async Task RevokeAsync(string token)
    {
        var refreshToken = await FindByTokenAsync(token);
        if (refreshToken != null && !refreshToken.IsRevoked)
        {
            refreshToken.IsRevoked = true;
            refreshToken.LastModifiedTime = DateTime.UtcNow;
            await _terraDbContext.SaveChangesAsync();
        }
    }
}